package com.yyfax.account.service;


import com.jaws.core.common.log.Log;
import com.jaws.core.common.util.DateUtil;
import com.yyfax.account.common.annotation.AccountTradeAnno;
import com.yyfax.account.common.enums.TableNameEnum;
import com.yyfax.account.common.enums.TableSequenceEnum;
import com.yyfax.account.common.enums.TradeTypeEnum;
import com.yyfax.account.common.exception.AccountExceptionCode;
import com.yyfax.account.common.util.TableSegmentUtils;
import com.yyfax.account.dao.AccountFlowDao;
import com.yyfax.account.dao.AccountInfoDao;
import com.yyfax.account.dao.AccountTradeFrozenDao;
import com.yyfax.account.domain.AccountFlow;
import com.yyfax.account.domain.AccountInfo;
import com.yyfax.account.domain.AccountTradeFrozen;
import com.yyfax.account.vo.ComplexTradeReq;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.List;

/**
 * 同时扣减账面余额和冻结余额 服务实现类
 *
 * @author liangqm
 * @date 2018/1/16 14:00
 * @since v1.0.0
 */
@AccountTradeAnno(TradeTypeEnum.UNFROZEN_REDUCE)
@Service
public class TradeUnfrozenServiceImpl extends BaseTradeService<ComplexTradeReq> {
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Resource
    private AccountInfoDao accountInfoDao;

    @Resource
    private AccountTradeFrozenDao tradeFrozenDao;

    @Resource
    private AccountFlowDao accountFlowDao;

    @Override
    public void checkBusiness(ComplexTradeReq req) {

        // 1.金额必须为整数
        if (req.getAmount() <= 0) {
            throw AccountExceptionCode.UNFROZEN_AMOUNT_NEGATIVE.exp(req.getTradeNo());
        }

        // 2.检查用户已开户
        AccountInfo account = accountInfoDao.queryAccountInfoByUser(req.getUserId());
        if (account == null || !account.getAccountNo().equals(req.getAccountNo())) {
            throw AccountExceptionCode.ACCOUNT_NOT_EXSITS.exp(req.getAccountNo());
        }
    }

    @Override
    public void batchCheckBusiness(ComplexTradeReq req, AccountInfo account) {
        final String op = "TradeUnfrozenServiceImpl.batchCheckBusiness";

        if (account == null || !account.getAccountNo().equals(req.getAccountNo())) {
            logger.error(Log.op(op).msg("账户不存在").kv("tradeNo", req.getTradeNo()).kv("accountNo", req.getAccountNo()).toString());
            throw AccountExceptionCode.ACCOUNT_NOT_EXSITS.exp(req.getAccountNo());
        }

        if (req.getAmount() <= 0) {
            logger.error(Log.op(op).msg("交易金额必须大于0").kv("tradeNo", req.getTradeNo()).kv("amount", req.getAmount()).toString());
            throw AccountExceptionCode.FROZEN_AMOUNT_NEGATIVE.exp(req.getAmount(), req.getTradeNo());
        }
    }

    @Transactional
    @Override
    public void doTrade(ComplexTradeReq req, Boolean isBatch) {
        final String op = "TradeUnfrozenServiceImpl.doTrade";
        logger.info(Log.op(op).msg("解冻扣减余额开始").kv("req", req).toString());

        // 1.业务检查
        if (!isBatch) {
            checkBusiness(req);
        }

        // 2.保存交易订单
        String segment = TableSegmentUtils.getTableSegment(TableNameEnum.ACCOUNT_TRADE_FROZEN, req.getUserId());
        // 唯一约束冲突标识位
        boolean duplicateKeyFlag = false;

        AccountTradeFrozen tradeFrozen = buildTradeFrozen(req);
        try {
            tradeFrozenDao.insert(tradeFrozen, segment);
        } catch (DuplicateKeyException e) {
            logger.info(Log.op(op).msg("唯一约束冲突").kv("tradeNo", req.getTradeNo()).toString(), e);
            duplicateKeyFlag = true;
        }

        // out_trade_no唯一索引冲突，trade_no唯一约束冲突
        if (duplicateKeyFlag) {
            AccountTradeFrozen existOrder = tradeFrozenDao.queryOrderByOutTradeNo(req.getTradeNo(), segment);
            if (existOrder == null) {
                throw AccountExceptionCode.SYS_ERROR.exp();
            }
            return;
        }

        // 3.驱动账户变更
        int result = accountInfoDao.updateTradeUnfrozen(req.getUserId(), req.getAccountNo(), req.getAmount());

        if (result != 1) {
            throw AccountExceptionCode.AMOUNT_NOT_ENOUGH.exp(req.getTradeNo(), req.getUserId(), req.getAmount());
        }

        // 4.生成账户流水
        if (!CollectionUtils.isEmpty(req.getFlowDataLs())) {
            List<AccountFlow> accountFlows = buildAccountFlow(req);
            for (AccountFlow accountFlow : accountFlows) {
                accountFlowDao.insert(accountFlow, segment);
            }
        }
        logger.info(Log.op(op).msg("解冻扣减余额结束").kv("req", req).toString());
    }

    private AccountTradeFrozen buildTradeFrozen(ComplexTradeReq req) {
        AccountTradeFrozen po = new AccountTradeFrozen();
        po.setUserId(req.getUserId());
        po.setAccountNo(req.getAccountNo());
        po.setAmount(req.getAmount());
        po.setTradeNo(commonIdUtils.generateId(TableSequenceEnum.ACCOUNT_TRADE_FROZEN));
        po.setOutTradeNo(req.getTradeNo());
        po.setOutBusinessNo(req.getBusinessNo());
        po.setOrignOutTradeNo("");
        po.setTradeTime(req.getTradeTime());
        po.setTradeType(req.getTradeType().getCode());
        po.setSource(req.getSource().getCode());
        po.setRemark(req.getRemark());
        po.setCreateTime(DateUtil.getCurrentDateTime());
        po.setUpdateTime(DateUtil.getCurrentDateTime());
        return po;
    }
}
